package BLC

import (
	"bytes"
	"crypto/sha256"
	"fmt"
	"math/big"
)

//目标难道值
//代表哈希前16位为0 ,才能满足条件
const targetBit = 16

//工作量证明POW
type ProofOfWork struct {
	Block  *Block   //对指定的区块进行验证
	Target *big.Int //大数据存储
}

//创建POW对象
func NewProofOfWork(block *Block) *ProofOfWork {
	target := big.NewInt(1)
	//左移
	target = target.Lsh(target, 256-targetBit)
	return &ProofOfWork{
		Block:  block,
		Target: target,
	}

}

//开始工作量证明(POW)
func (self *ProofOfWork) Run() ([]byte, int64) {
	var nonce int64 = 0

	var hash [32]byte
	var hashInt big.Int //存储hash 和target 数据进行比较
	for {
		nonce++
		//数据拼接
		dataBytes := self.prepareData(nonce)
		hash = sha256.Sum256(dataBytes)
		hashInt = *hashInt.SetBytes(hash[:])

		//
		if self.Target.Cmp(&hashInt) == 1 {
			fmt.Printf(" 哈希碰撞 : \t %x \n", hash)
			fmt.Printf(" 碰撞次数 : \t %d \n", nonce)
			break
		}

	}

	return hash[:], nonce
}

//区块拼接
func (self *ProofOfWork) prepareData(nonce int64) []byte {
	data := bytes.Join([][]byte{
		self.Block.PrevBlockHash,
		self.Block.HashTransaction(),
		IntToHex(self.Block.TimeStamp),
		IntToHex(self.Block.Height),
		IntToHex(nonce),
		IntToHex(targetBit),
	}, []byte{})

	return data

}
